package com.hyper_yang._05_juc.chap02;


import java.util.concurrent.locks.ReentrantLock;

/**
 * 演示：JUC中Lock接口的子类： ReentrantLock使用
 */

//封装资源类：卖票的类
class Ticket {
    private int number = 20; //票数
    //private ReentrantLock lock = new ReentrantLock(); //可重入的互斥锁   默认非公平锁。
    private ReentrantLock lock = new ReentrantLock(true); //可重入的互斥锁   true公平锁。
    //卖票
    public void sale() {
        lock.lock(); //加锁
        System.out.println("加锁....");

        //票不能出现负数  即：不能超卖
        if (number <= 0) {
            System.out.println(" 售罄 ");
            lock.unlock();
            System.out.println("解锁....");
            return;
        }

        try {
            System.out.println(Thread.currentThread().getName() + " 开始买票-剩余 = " + number);
            Thread.sleep(100);
            System.out.println(Thread.currentThread().getName() + " 卖掉一张票，然后剩余 = " + --number); // ++ -- 不是原子性，不安全

            check(); //根据锁可重入性，对剩余票数进行检查。


        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock(); //解锁
            System.out.println("解锁....");
        }
    }

    private void check() {
        lock.lock(); //加锁
        System.out.println("加锁2....");
        System.out.println(" 锁重入了 剩余票数： "+number);
        lock.unlock(); //解锁
        System.out.println("解锁2....");
    }
}


/**
 * 多线程编程模板：
 * 模板1：
 * 1.高内聚、低耦合
 * 2、线程 操作 资源类
 * 案例：卖票程序，三个窗口(线程)来卖20张票。
 */
public class SaleTicket {
    public static void main(String[] args) {
        //创建资源列对象
        Ticket ticket = new Ticket();

        //卖票窗口A
        new Thread(() -> {
            for (int i = 0; i < 20; i++) {
                ticket.sale(); //操作
            }
        }, "A").start();

        //卖票窗口B
        new Thread(() -> {
            for (int i = 0; i < 20; i++) {
                ticket.sale(); //操作
            }
        }, "B").start();

        //卖票窗口C
        new Thread(() -> {
            for (int i = 0; i < 20; i++) {
                ticket.sale(); //操作
            }
        }, "C").start();
    }
}
